package com.mmall.common.spring.handler;

import com.common.framework.exception.AuthorizedException;
import com.common.framework.exception.BusinessException;
import com.common.framework.exception.SystemException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolationException;
import java.util.List;

@ControllerAdvice(annotations = Controller.class)
public class GlobalExceptionHandler {

    @Autowired
    private MessageSource messageSource;

    private ApplicationError applicationError(String errorCode) {
        String message = getErrorMessage(errorCode);
        return ApplicationError.builder()
            .error(message)
            .code(errorCode)
            .build();
    }

    private String getErrorMessage(String exceptionCode) {
        try {
            return messageSource.getMessage(exceptionCode, null, null);
        } catch (Exception e) {
            return exceptionCode;
        }
    }

    /***
     * 同一处理 springboot @valid 提示的错误信息
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ApplicationError mapMethodArgumentNotValidException(BindException e) {
        List<ObjectError> errorList = e.getBindingResult().getAllErrors();
        return ApplicationError.builder()
            .error(errorList.get(0).getDefaultMessage())
            .code("PARAMETER_MISS")
            .build();
    }

    /**
     * @Validated 方法参数错误提示
     * @param e
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ApplicationError mapConstraintViolationException(ConstraintViolationException e) {
        return ApplicationError.builder()
                .error(e.getMessage())
                .code("PARAMETER_MISS")
                .build();
    }

    /***
     * 同一处理 springboot 参数缺失
     * @param e
     * @return
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ApplicationError mapMissingServletRequestParameterException(MissingServletRequestParameterException e) {
        return ApplicationError.builder()
            .error(e.getParameterName().concat(" 必填"))
            .code("PARAMETER_MISS")
            .build();
    }

    /***
     * 业务失败
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ResponseBody
    public ApplicationError mapApiException(BusinessException e) {
        return applicationError(e.getCode());
    }

    /**
     * 服务器内部错误
     * @param e
     * @return
     */
    @ExceptionHandler(SystemException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ResponseBody
    public ApplicationError mapSystemException(SystemException e) {
        return ApplicationError.builder()
                .error("服务器内部错误")
                .code("SYSTEM_EXCEPTION")
                .build();
    }

    /***
     * 鉴权失败
     * @param e
     * @return
     */
    @ExceptionHandler(AuthorizedException.class)
    @ResponseStatus(HttpStatus.FORBIDDEN)
    @ResponseBody
    public ApplicationError unAuthorizedException(AuthorizedException e) {
        return ApplicationError.builder().error("请重新登录").code("PLEASE_LOGIN").build();
    }

}

